package ru.fadeev.crammer.ui.window;

import java.awt.*;
import java.awt.event.*;
import java.util.Vector;

import javax.swing.*;
import javax.swing.event.*;
import javax.swing.table.AbstractTableModel;

import ru.fadeev.crammer.Settings;
import ru.fadeev.crammer.Utils;
import ru.fadeev.crammer.data.Phrase;
import ru.fadeev.crammer.data.PhrasesBatch;
import ru.fadeev.crammer.ui.ArrowOptionPane;
import ru.fadeev.crammer.ui.BasicCellRenderer;
import ru.fadeev.crammer.ui.CrammerToolbarButton;
import ru.fadeev.crammer.ui.LimitedPlainDocument;
import ru.fadeev.crammer.ui.TableTextFieldFactory;


/**
 * EditBatchDialog provides GUI for adding, editing and deleting phrases in
 * PhrasesBatch.
 * @author Konstantin Fadeyev
 */
public class EditBatchDialog extends JDialog {
	// Constants
	public final static int BTN_OK = 100;
	public final static int BTN_CANCEL = 101;

	// UI Components
	private JPanel mainPanel;
	private JPanel topPanel;
	private JLabel batchNameLabel;
	private JTextField batchNameTextField;
	
	private JToolBar phrasesToolBar;
    private JButton addPhraseButton;
    private JButton deletePhraseButton;
	
	private JScrollPane phrasesScrollPane;
	private JTable phrasesTable;
    private PhrasesTableModel phrasesTableModel;
	   
	private JPanel bottomPanel;
	private JPanel okCancelButtonsPanel;
    private JButton okButton;
    private JButton cancelButton;

    // User fields
    private PhrasesBatch batch;
    private Vector<Integer> deletedPhrases;
	private int pressedButton;
    
	
	/**
	 * Contstructs EditBatchDialog and initializes it with batch
	 * @param owner parent window
	 * @param batch batch to edit phrases in
	 */
    public EditBatchDialog(Dialog owner, PhrasesBatch batch) {
        super(owner,true);
        
        Dimension screenSize = Toolkit.getDefaultToolkit().getScreenSize();
        setSize(800, 500);
        setLocation((screenSize.width-800)/2, (screenSize.height-500)/3);
        
        this.batch = batch;
        deletedPhrases = new Vector<Integer>();
        batch.loadPhrases();
        
        pressedButton = BTN_CANCEL;
       	setTitle("Editing batch");
       
        initComponents();
        placeComponents();
        refreshPhrasesButtons();
    }
    
    
    /**
     * Initializes UI Components of the dialog
     */
    private void initComponents() {
        mainPanel = new JPanel();
        topPanel = new JPanel(); 
        batchNameLabel = new JLabel("Batch name:");  
        batchNameTextField = new JTextField();
        LimitedPlainDocument batchNameDocument = 
			new LimitedPlainDocument(Settings.BATCH_NAME_MAX_LENGTH);
        batchNameTextField.setDocument(batchNameDocument);
        batchNameTextField.setText(batch.getName());
    	
        bottomPanel = new JPanel();

        // Phrases buttons
		ImageIcon addPhraseIcon = new ImageIcon("icons/16/add.png");
		addPhraseButton = new CrammerToolbarButton(addPhraseIcon, 
				"Insert Phrase");
		addPhraseButton.addActionListener(
			    new AbstractAction() {
			        public void actionPerformed(ActionEvent ev) {
			        	insertPhrase();
			        }
			    });

		ImageIcon deletePhraseIcon = new ImageIcon("icons/16/delete.png");
        deletePhraseButton = new CrammerToolbarButton(deletePhraseIcon, 
        		"Delete Phrase");
        deletePhraseButton.addActionListener(
			    new AbstractAction() {
			        public void actionPerformed(ActionEvent ev) {
			        	deletePhrases();
			        }
			    });

		// ToolBar
		phrasesToolBar = new JToolBar(JToolBar.HORIZONTAL);
		phrasesToolBar.setFloatable(false);        
		phrasesToolBar.add(addPhraseButton);
		phrasesToolBar.add(deletePhraseButton);
		
		// Phrases Table
    	phrasesTableModel = new PhrasesTableModel(batch);    
    	phrasesTable = new JTable(phrasesTableModel);
    	phrasesTable.putClientProperty("JTable.autoStartsEdit", 
    			Boolean.FALSE);
    	phrasesTable.putClientProperty("terminateEditOnFocusLost", 
    			Boolean.TRUE);

    	phrasesTable.getSelectionModel().setSelectionMode(ListSelectionModel.SINGLE_SELECTION);
    	
    	ListSelectionListener selectionListener = new ListSelectionListener() {
	    	public void valueChanged(ListSelectionEvent e) {
	    		refreshPhrasesButtons();
	    	}
    	};
    	phrasesTable.getSelectionModel().addListSelectionListener(selectionListener);
    	phrasesTable.getColumnModel().getSelectionModel()
            					.addListSelectionListener(selectionListener);
    	
    	BasicCellRenderer cellRenderer = new BasicCellRenderer();
    	phrasesTable.setDefaultRenderer(String.class, cellRenderer);
    	
    	phrasesTable.getTableHeader().setReorderingAllowed(false);
    	
        JTextField phraseTextField = 
        	TableTextFieldFactory.createTableTextField();
    	LimitedPlainDocument phraseDocument = 
			new LimitedPlainDocument(Settings.PHRASE_MAX_LENGTH);
    	phraseTextField.setDocument(phraseDocument);

        DefaultCellEditor testEditor = new DefaultCellEditor(phraseTextField);
        testEditor.setClickCountToStart(2);
        
        phrasesTable.setDefaultEditor(String.class, testEditor);
    	 
    	phrasesScrollPane = new JScrollPane(phrasesTable);    	
    	
        // Ok, Cancel buttons
        okButton = new JButton("OK");
        getRootPane().setDefaultButton(okButton);
        
		cancelButton = new JButton("Cancel");
        bottomPanel = new JPanel();   
        okCancelButtonsPanel = new JPanel();        
        
        okButton.addActionListener(
			    new AbstractAction() {
			        public void actionPerformed(ActionEvent ev) {
			        	okButtonAction();
			        }
			    });
        
        cancelButton.addActionListener(
			    new AbstractAction() {
			        public void actionPerformed(ActionEvent ev) {
			           	cancelButtonAction();
			        }
		        });
        
        setContentPane(mainPanel);
    }

    
    /**
     * Places UI components using different layout managers
     */
    private void placeComponents() {
    	mainPanel.setLayout(new BorderLayout());
    	mainPanel.add(topPanel, BorderLayout.NORTH);
    	mainPanel.add(phrasesScrollPane, BorderLayout.CENTER);
    	mainPanel.add(bottomPanel, BorderLayout.SOUTH);
    
    	topPanel.setPreferredSize(new Dimension(30,54));
    	topPanel.setLayout(null);
    	topPanel.add(batchNameLabel);
    	topPanel.add(batchNameTextField);
    	topPanel.add(phrasesToolBar);
    	
    	batchNameLabel.setBounds(10, 5, 70, 20);
    	batchNameTextField.setBounds(80, 5, 300, 20);
    	phrasesToolBar.setBounds(0, 30, 200, 25);
    	
    	bottomPanel.setPreferredSize(new Dimension(200, 40));
    	bottomPanel.setLayout(new BorderLayout());
    	bottomPanel.add(okCancelButtonsPanel, BorderLayout.EAST);
 
    	okCancelButtonsPanel.setPreferredSize(new Dimension(210, 40));
    	okCancelButtonsPanel.setLayout(null);
    	okCancelButtonsPanel.add(okButton);
    	okCancelButtonsPanel.add(cancelButton);
    	
    	okButton.setBounds(10, 10, 90, 20);
    	cancelButton.setBounds(110, 10, 90, 20);
    }
    
    
    /**
     * Ok button action handler. Validates entered values.
     */
    private void okButtonAction() {
    	Utils.finishTableEditing(phrasesTable);
    	
    	batch.setName(batchNameTextField.getText().trim());
    	for(int i = batch.size() - 1; i >= 0; i--) {
    		if(batch.getPhrase(i).getText().trim().equals("")) {
    			batch.removePhrase(i);
    		}
    	}

    	pressedButton = BTN_OK;
    	setVisible(false);
    }
      
    
    /**
     * Cancel button action handler. Closes dialog.
     */
    private void cancelButtonAction() {
        pressedButton = BTN_CANCEL;
        setVisible(false);
    }
      
    
    /**
     * After dialog is closed, call this function to find out which option
     * user picked (OK or Cancel)
     * @return pressed button (one of BTN_OK, BTN_CANCEL)
     */
    public int getPressedButton() {
    	return pressedButton;
    }
    
    /**
     * Inserts new empty phrase record in the batch  
     */
    private void insertPhrase() {
    	Utils.finishTableEditing(phrasesTable);
    	
    	int rowIndex = phrasesTable.getSelectedRow();
    	int columnIndex = phrasesTable.getSelectedColumn();
		if(rowIndex < 0) {
			rowIndex = batch.getPhrasesCount();
		}
		if(columnIndex < 0) {
			columnIndex = 0;
		}

		Phrase newPhrase = new Phrase(0,"", Phrase.INSERTED);
		batch.insertPhrase(newPhrase, rowIndex);

		phrasesTableModel.fireTableDataChanged();
		phrasesTable.setRowSelectionInterval(rowIndex, rowIndex);
		phrasesTable.setColumnSelectionInterval(columnIndex, columnIndex);
		phrasesTable.requestFocus();
    }
       
    
    /**
     * Deletes selected phrases from sheet. Actually phrases are not deleted,
     * rather information about their deletion goes to deletedPhrases vector, 
     * and if user presses cancel button, batch remains intact.
     */
    private void deletePhrases() {
    	Utils.finishTableEditing(phrasesTable);
    	
		int n = ArrowOptionPane.showConfirmDialog(this,
				"Selected phrases will be deleted.\n" +
                "Are you sure?", "Are you sure?", 
                JOptionPane.YES_NO_OPTION);
	    switch(n) {
        case JOptionPane.OK_OPTION:
        	int[] indices = phrasesTable.getSelectedRows();
        	int columnIndex = phrasesTable.getSelectedColumn();
        	
        	int indexToSelect = indices[indices.length-1] - indices.length + 1;
        	for(int i=0; i<indices.length; i++) {
        		Phrase phrase = batch.getPhrase(indices[i]);
        		deletedPhrases.addElement(new Integer(phrase.getId()));
        	}
        	batch.removePhrases(indices);
        	phrasesTableModel.fireTableDataChanged();
			if(indexToSelect == batch.size()) {
				indexToSelect = indexToSelect - 1;
			}
			if(indexToSelect >= 0) {
				phrasesTable.setRowSelectionInterval(indexToSelect, indexToSelect);
			}
			if(columnIndex >= 0) {
				phrasesTable.setColumnSelectionInterval(columnIndex, columnIndex);
			}
			phrasesTable.requestFocus();
			
            break;
        default:      
            return;
	    }    	
    }
 
    
    /**
     * Enable/disable toolbars buttons depending on selected phrases.
     */
    public void refreshPhrasesButtons() {
    	if(phrasesTable.getSelectedRow() < 0) {
    		deletePhraseButton.setEnabled(false);
    	} else { 
    		deletePhraseButton.setEnabled(true);
    	}
    }
    
    
    /**
     * After dialog is closed, call this function to get list of phrases that
     * was chosen to delete
     * @return vector of phrases to delete
     */
    public Vector<Integer> getDeletedPhrases() {
    	return deletedPhrases;
    }
    
    
    /**
     * PhrasesTableModel class represents table model
     * for phrases table in EditBatchDialog
     * @author Konstantin Fadeyev
     *
     */
    private class PhrasesTableModel extends AbstractTableModel {
    	PhrasesBatch batch;
    	
    	public PhrasesTableModel(PhrasesBatch batch) {
    		super();
    		this.batch = batch;
    	}

    	public int getRowCount() {
             return batch.size();
    	}

    	public int getColumnCount() {
    		return 1;
    	}

    	public String getColumnName(int num) {
            return "Phrase";
    	}

        public boolean isCellEditable(int rowIndex, int columnIndex) {
    		return true;
        }

    	public Object getValueAt(int row, int column) {
    		if(row < batch.size()) {
    			return batch.getPhrase(row).getText();
    		} else {
    			return "";
    		}
    	}

    	public void setValueAt(Object aValue, int rowIndex, int columnIndex) {
    		Phrase phrase = batch.getPhrase(rowIndex);
    		phrase.setText((String)aValue);
    		if (phrase.getStatus() == Phrase.NO_CHANGE) {
    			phrase.setStatus(Phrase.UPDATED);
    		}
    	}

        public Class<?> getColumnClass(int c) {
            return getValueAt(0, c).getClass();
        }
    }
}
